package com.meshnetics.gb.stack.mac.primitives;

import com.meshnetics.gb.stack.core.event.StackEventType;
import com.meshnetics.gb.stack.core.event.StackRequest;
import com.meshnetics.gb.stack.mac.RadioMACStackLayer;
import com.meshnetics.gb.type.impl.zcl.*;

import java.nio.ByteBuffer;

/**
 * WRITE DESCRIPTION HERE
 *
 * @author AKovylin
 */
public class MACStartRequest extends StackRequest implements MACCommand, MACReplyAwaited {
    public static final byte CODE = 0x5d;

    private final UInt panId;
    private final UInt logicalChannel;
    private final UInt beaconOrder;
    private final UInt superframeOrder;
    private final Bool panCoordinator;
    private final Bool batteryLifeExtension;
    private final Bool coordRealignment;
    private final Bool securityEnable;

    public MACStartRequest(int panId, int logicalChannel, int beaconOrder, int superframeOrder,
                           boolean panCoordinator, boolean batteryLifeExtension,
                           boolean coordRealignment, boolean securityEnable) {
        this((short) (panId & 0xffff), (byte) (logicalChannel & 0xff),
                (byte) (beaconOrder & 0xff), (byte) (superframeOrder & 0xff),
                panCoordinator, batteryLifeExtension, coordRealignment, securityEnable);
    }

    public MACStartRequest(short panId, byte logicalChannel, byte beaconOrder, byte superframeOrder,
                           boolean panCoordinator, boolean batteryLifeExtension,
                           boolean coordRealignment, boolean securityEnable) {
        this(new Short(panId), new Byte(logicalChannel), new Byte(beaconOrder), new Byte(superframeOrder),
                Boolean.valueOf(panCoordinator), Boolean.valueOf(batteryLifeExtension),
                Boolean.valueOf(coordRealignment), Boolean.valueOf(securityEnable));
    }

    public MACStartRequest(Short panId, Byte logicalChannel, Byte beaconOrder, Byte superframeOrder,
                           Boolean panCoordinator, Boolean batteryLifeExtension,
                           Boolean coordRealignment, Boolean securityEnable) {
        this((UInt) TypeUInt.UINT_16.fromObject(panId), (UInt) TypeUInt.UINT_8.fromObject(logicalChannel),
                (UInt) TypeUInt.UINT_8.fromObject(beaconOrder), (UInt) TypeUInt.UINT_8.fromObject(superframeOrder),
                (Bool) TypeBool.BOOLEAN.fromObject(panCoordinator),
                (Bool) TypeBool.BOOLEAN.fromObject(batteryLifeExtension),
                (Bool) TypeBool.BOOLEAN.fromObject(coordRealignment),
                (Bool) TypeBool.BOOLEAN.fromObject(securityEnable));
    }

    public MACStartRequest(UInt panId, UInt logicalChannel, UInt beaconOrder, UInt superframeOrder,
                           Bool panCoordinator, Bool batteryLifeExtension,
                           Bool coordRealignment, Bool securityEnable) {
        super("macStartRequest", StackEventType.LME_TYPE);
        if (panId == null) {
            throw new NullPointerException("panId is null");
        }
        if (logicalChannel == null) {
            throw new NullPointerException("logicalChannel is null");
        }
        if (beaconOrder == null) {
            throw new NullPointerException("beaconOrder is null");
        }
        if (superframeOrder == null) {
            throw new NullPointerException("superframeOrder is null");
        }
        if (panCoordinator == null) {
            throw new NullPointerException("panCoordinator is null");
        }
        if (batteryLifeExtension == null) {
            throw new NullPointerException("batteryLifeExtension is null");
        }
        if (coordRealignment == null) {
            throw new NullPointerException("coordRealignment is null");
        }
        if (securityEnable == null) {
            throw new NullPointerException("securityEnable is null");
        }
        int checkInt = ((Number) logicalChannel.toObject()).intValue();
        if (checkInt < 0 || checkInt > 0x1a) {
            throw new IllegalArgumentException("invalid logicalChannel, must be in range 0x00-0x1a");
        }
        checkInt = ((Number) beaconOrder.toObject()).intValue();
        if (checkInt < 0 || checkInt > 15) {
            throw new IllegalArgumentException("invalid beaconOrder, must be in range 0-15");
        }
        checkInt = ((Number) superframeOrder.toObject()).intValue();
        if (checkInt < 0 || checkInt > 15) {
            throw new IllegalArgumentException("invalid superframeOrder, must be in range 0-15");
        }
        if (panCoordinator.isInvalid()) {
            throw new IllegalArgumentException("invalid panCoordinator");
        }
        if (batteryLifeExtension.isInvalid()) {
            throw new IllegalArgumentException("invalid batteryLifeExtension");
        }
        if (coordRealignment.isInvalid()) {
            throw new IllegalArgumentException("invalid coordRealignment");
        }
        if (securityEnable.isInvalid()) {
            throw new IllegalArgumentException("invalid securityEnable");
        }
        this.panId = panId.convert(TypeUInt.UINT_16);
        this.logicalChannel = logicalChannel.convert(TypeUInt.UINT_8);
        this.beaconOrder = beaconOrder.convert(TypeUInt.UINT_8);
        this.superframeOrder = superframeOrder.convert(TypeUInt.UINT_8);
        this.panCoordinator = panCoordinator;
        this.batteryLifeExtension = batteryLifeExtension;
        this.coordRealignment = coordRealignment;
        this.securityEnable = securityEnable;
    }

    public UInt getPanIdType() {
        return panId;
    }

    public UInt getLogicalChannelType() {
        return logicalChannel;
    }

    public UInt getBeaconOrderType() {
        return beaconOrder;
    }

    public UInt getSuperframeOrderType() {
        return superframeOrder;
    }

    public Bool getPanCoordinatorType() {
        return panCoordinator;
    }

    public Bool getCoordRealignmentType() {
        return coordRealignment;
    }

    public Bool getBatteryLifeExtensionType() {
        return batteryLifeExtension;
    }

    public Bool getSecurityEnableType() {
        return securityEnable;
    }

    public Short getPanId() {
        return (Short)panId.toObject();
    }

    public Byte getLogicalChannel() {
        return (Byte)logicalChannel.toObject();
    }

    public Byte getBeaconOrder() {
        return (Byte)beaconOrder.toObject();
    }

    public Byte getSuperframeOrder() {
        return (Byte)superframeOrder.toObject();
    }

    public Boolean getPanCoordinator() {
        return (Boolean) panCoordinator.toObject();
    }

    public Boolean getCoordRealignment() {
        return (Boolean) coordRealignment.toObject();
    }

    public Boolean getBatteryLifeExtension() {
        return (Boolean) batteryLifeExtension.toObject();
    }

    public Boolean getSecurityEnable() {
        return (Boolean) securityEnable.toObject();
    }

    public byte getCode() {
        return CODE;
    }

    public int getSize(RadioMACStackLayer layer) {
        return 5;
    }

    public void serialize(ByteBuffer bb, RadioMACStackLayer layer) {
        BitmapEditor editor = new BitmapEditor(TypeBitmap.BITMAP_8);
        editor.setBits(0, 4, ((Number) beaconOrder.toObject()).intValue());
        editor.setBits(4, 8, ((Number) superframeOrder.toObject()).intValue());
        Bitmap b1 = editor.create();
        editor.setBits(0, 8, 0);
        editor.setBit(0, panCoordinator.toObject() == Boolean.TRUE);
        editor.setBit(1, batteryLifeExtension.toObject() == Boolean.TRUE);
        editor.setBit(2, coordRealignment.toObject() == Boolean.TRUE);
        editor.setBit(3, securityEnable.toObject() == Boolean.TRUE);
        Bitmap b2 = editor.create();
        panId.serialize(bb);
        logicalChannel.serialize(bb);
        b1.serialize(bb);
        b2.serialize(bb);
    }

    public String toString() {
        return getName() + '(' + panId + ',' + logicalChannel + ',' + beaconOrder + ',' + superframeOrder + ',' +
                panCoordinator + ',' + batteryLifeExtension + ',' + coordRealignment + ',' + securityEnable + ')';
    }
}
